<script setup lang="ts">
// 定义print函数有泛型，传入参数是这个类型，返回的也是这个类型
// 泛型一种类型的泛指
function print<T>(arg:T):T{
  console.log(arg);
  return arg;
}
// 自动推断
print(123)
// 手动指定
print<string>("abc")

// 定义一个交换函数有泛型T和U，参数是一个元祖有两个数据类型T和U
// 返回的值是一个元祖类型是[U,T]
function swap<T,U>(arg:[T,U]):[U,T]{
  console.log('arg',arg);
  return [arg[1],arg[0]]
}
var re = swap([1,"abc"])
console.log("re",re)

interface Ilen{
  length:number;
}
// 定义printIt方法 有泛型T 必须基础Ilen 有length属性
function printIt<T extends Ilen>(arg:T){
  // 打印长度
  console.log(arg.length);
}
printIt("abc");
printIt([1,23]);
printIt({name:"mumu",length:5})
// printIt(false);

// 定义一个栈 有一个泛型是T
class Stack<T> {
  // 私有数据 data为T类型的数组
  private data:T[] = [];
  // 入栈 添加元素必须是 T类型
  push(item:T){
    return this.data.push(item);
  }
  // 出栈，移除返回的元素必须T类型
  pop():T|undefined{
    return this.data.pop()
  }
}
// 定义创建栈方法指定类型为string
const s1 = new Stack<string>()
s1.push('abc');
s1.push("def");

const s2 = new Stack<number>()
s2.push(123)
s2.pop()

// 定义接口 IkeyValue 两个泛型 T与U
interface IkeyValue<T,U>{
  key:T, //key的值必须是T类型
  value:U// value 值必须是U类型
}
// 定义对象obj1 是IkeyValue类型 T泛型指定为 string，U类型指定为number
var obj1:IkeyValue<string,number> ={
  key:"学习",
  value:100
}
var obj2:IkeyValue<string,boolean> ={
  key:"学习",
  value:false
}
</script>

<template>
  <main>
   <h1>TypeScript学习-泛型</h1>
   <p>{{obj1}}</p>
   <p>{{obj2}}</p>
  </main> 
</template>

